/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 owned_ptr.h

	$Header: /heroes4/owned_ptr.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( OWNED_PTR_H_INCLUDED )
#define OWNED_PTR_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdlib>
#include <memory>

#include "uncopyable.h"

// --------------------------------------------------------------------------
// t_owned_ptr class template
// --------------------------------------------------------------------------

template < typename t_elem >
class t_owned_ptr : private t_uncopyable
{
public:
	// Types
	typedef t_elem element_type;

	// Constructors/Destructor
	explicit t_owned_ptr( t_elem * ptr = 0 );
	t_owned_ptr( std::auto_ptr< t_elem > ptr );
	~t_owned_ptr();

	// Member functions
	t_elem *	get() const;
	t_elem *	release();
	void		reset( t_elem * new_ptr = 0 );
	void		swap( t_owned_ptr & other );

	// Operators
	t_elem &		operator*() const;
	t_elem *		operator->() const;

	t_owned_ptr &	operator=( std::auto_ptr< t_elem > new_ptr );

private:
	// Data members
	t_elem *	m_ptr;
};

// --------------------------------------------------------------------------
// t_owned_ptr members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_ptr< t_elem >::t_owned_ptr( t_elem * ptr )
	:	m_ptr( ptr )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_ptr< t_elem >::t_owned_ptr( std::auto_ptr< t_elem > ptr )
	:	m_ptr( ptr.release() )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_ptr< t_elem >::~t_owned_ptr()
{
	delete m_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_ptr< t_elem >::get() const
{
	return m_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_ptr< t_elem >::release()
{
	t_elem * result = m_ptr;
	m_ptr = 0;
	return result;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline void t_owned_ptr< t_elem >::reset( t_elem * new_ptr )
{
	assert( new_ptr == 0 || new_ptr != m_ptr );
	std::swap( m_ptr, new_ptr );
	delete new_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline void t_owned_ptr< t_elem >::swap( t_owned_ptr & other )
{
	std::swap( m_ptr, other.m_ptr );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem & t_owned_ptr< t_elem >::operator*() const
{
	return *m_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_ptr< t_elem >::operator->() const
{
	return m_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_ptr< t_elem > & t_owned_ptr< t_elem >::operator=(
	std::auto_ptr< t_elem > new_ptr )
{
	assert( new_ptr.get() == 0 || new_ptr.get() != m_ptr );
	delete m_ptr;
	m_ptr = new_ptr.release();
	return *this;
}

// --------------------------------------------------------------------------
// t_owned_array class template
// --------------------------------------------------------------------------

template < typename t_elem >
class t_owned_array : private t_uncopyable
{
public:
	// Types
	typedef t_elem element_type;

	// Constructor/Destructor
	explicit t_owned_array( t_elem * array = 0);
	~t_owned_array();

	// Member functions
	t_elem *	get() const;
	t_elem *	release();
	void		reset( t_elem * new_array );
	void		swap( t_owned_array & other );

	// Operators
	t_elem &	operator[]( ptrdiff_t index ) const;

private:
	// Data members
	t_elem *	m_array;
};

// --------------------------------------------------------------------------
// t_owned_array members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_array< t_elem >::t_owned_array( t_elem * array )
	:	m_array( array )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_array< t_elem >::~t_owned_array()
{
	delete [] m_array;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_array< t_elem >::get() const
{
	return m_array;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_array< t_elem >::release()
{
	t_elem * result = m_array;
	m_array = 0;
	return result;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline void t_owned_array< t_elem >::reset( t_elem * new_array )
{
	assert( new_array == 0 || new_array != m_array );
	std::swap( m_array, new_array );
	delete [] new_array;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline void t_owned_array< t_elem >::swap( t_owned_array & other )
{
	std::swap( m_array, other.m_array );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem & t_owned_array< t_elem >::operator[]( ptrdiff_t index ) const
{
	return m_array[ index ];
}

// --------------------------------------------------------------------------
// t_owned_malloc_ptr class template
// --------------------------------------------------------------------------

template < typename t_elem >
class t_owned_malloc_ptr : private t_uncopyable
{
public:
	// Types
	typedef t_elem element_type;

	// Constructors/Destructor
	explicit t_owned_malloc_ptr( t_elem * ptr = 0 );
	~t_owned_malloc_ptr();

	// Member functions
	t_elem *	get() const;
	t_elem *	release();
	void		reset( t_elem * new_ptr = 0 );
	void		swap( t_owned_malloc_ptr & other );

	// Operators
	t_elem &		operator*() const;
	t_elem *		operator->() const;

private:
	// Data members
	t_elem *	m_ptr;
};

// --------------------------------------------------------------------------
// t_owned_malloc_ptr members
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_malloc_ptr< t_elem >::t_owned_malloc_ptr( t_elem * ptr )
	:	m_ptr( ptr )
{
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_owned_malloc_ptr< t_elem >::~t_owned_malloc_ptr()
{
	free( m_ptr );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_malloc_ptr< t_elem >::get() const
{
	return m_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_malloc_ptr< t_elem >::release()
{
	t_elem * result = m_ptr;
	m_ptr = 0;
	return result;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline void t_owned_malloc_ptr< t_elem >::reset( t_elem * new_ptr )
{
	assert( new_ptr == 0 || new_ptr != m_ptr );
	std::swap( m_ptr, new_ptr );
	free( new_ptr );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline void t_owned_malloc_ptr< t_elem >::swap( t_owned_malloc_ptr & other )
{
	std::swap( m_ptr, other.m_ptr );
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem & t_owned_malloc_ptr< t_elem >::operator*() const
{
	return *m_ptr;
}

// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
template < typename t_elem >
inline t_elem * t_owned_malloc_ptr< t_elem >::operator->() const
{
	return m_ptr;
}

#endif // !defined( OWNED_PTR_H_INCLUDED )
